package edu.hit.pact.pgse.crawler.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.hit.pact.pgse.util.Utilities;

public class BufferedQueue<T> {
	private Log logger;
	private LinkedBlockingQueue<T> tailQueue;
	private ArrayList<String> objectFiles;
	private int objectsOneFile;
	
	public void setDead(){
		tailQueue = null;

		for (String fileName:objectFiles){
			File file = new File(fileName);
			logger.info("delete file " + fileName);
			file.delete();
		}
		objectFiles = null;
		logger = null;
	}
	
	public BufferedQueue(int objectsOneFile) {
		super();
		this.tailQueue = new LinkedBlockingQueue<T>();
		this.objectFiles = new ArrayList<String>();
		this.logger = LogFactory.getLog(BufferedQueue.class);
		this.objectsOneFile = objectsOneFile;
	}

	public void addOneObject(T obj) throws InterruptedException {
//		logger.info("add " + urlUnit.getLink() + " to the queue");
		if (tailQueue.size() < objectsOneFile-1)
			tailQueue.put(obj);
		else if (tailQueue.size() == objectsOneFile-1) {// 加入新的urlUnit之后就变成lengthLimit，要向硬盘写入
			tailQueue.put(obj);
			storeObject(tailQueue);
			tailQueue = new LinkedBlockingQueue<T>();
		} else {
			logger.info("The size of tail queue is greater than 1000, something wrong mush happen");
		}
	}
	
	public boolean isEmpty(){
		if (objectFiles.size() ==0 && tailQueue.size() ==0)
			return true;
		return false;
	}

	public LinkedBlockingQueue<T> getHeadQueue() {
		if (this.objectFiles.size() == 0) {
			logger.info("no buffer file, get " +tailQueue.size() + " objects from tail queue");	
			LinkedBlockingQueue<T> tmp = (LinkedBlockingQueue<T>) tailQueue;
			tailQueue = new LinkedBlockingQueue<T>();
			return tmp;
		}

		LinkedBlockingQueue<T> headQueue = (LinkedBlockingQueue<T>) loadObject();
		logger.info("has buffer file, get " +headQueue.size() + " objects from buffer queue");	
		return headQueue;
	}

	public int getObjectsNumber(){
		return objectFiles.size()*objectsOneFile+tailQueue.size();
	}
	
	private Object loadObject() {
		Object obj = null;
		String fileName = this.objectFiles.remove(0);

		try {
			ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
			obj = in.readObject();
			in.close();

			File file = new File(fileName);
			logger.info("delete file " + fileName);
			file.delete();
		} catch (Exception e) {
			logger.error("load object meets exception", e);
		}// end if;

		return obj;
	}

	private boolean storeObject(Object obj) {
		try {
			String fileName = "buffer/BufferFile_" + Math.random();
			this.objectFiles.add(fileName);
			Utilities.createdDir("buffer");
			ObjectOutputStream out = new ObjectOutputStream(
					new FileOutputStream(fileName));
			out.writeObject(obj);
			out.close();
			logger.info("create a new file "+fileName);
		} catch (IOException e) {
			logger.error("store buffer object meets exception", e);
			return false;
		}// end try

		return true;
	}
	
	
}
